from fastapi import FastAPI, Request, HTTPException
from fastapi.responses import PlainTextResponse, Response
from base import WXBizMsgCrypt 
import xmltodict
import logging
import time
import xml.etree.ElementTree as ET
import urllib.parse  # 添加URL解码库
 
# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
 
app = FastAPI()
 
# 企业微信配置
TOKEN = "123456789"  # 设置的Token
ENCODING_AES_KEY = "jWmYm7qr5nMoAUwZRjGtBxmz3KA1tkAj3ykkR6q2B2C" #设置密钥
CORP_ID = "wwd3eb9a8223709ae8"  # 企业ID

# TOKEN = "hJqcu3uJ9Tn2gXPmxx2w9kkCkCE2EPYo"  # 设置的Token
# ENCODING_AES_KEY = "6qkdMrq68nTKduznJYO1A37W2oEgpkMUvkttRToqhUt" #设置密钥
# CORP_ID = "ww1436e0e65a779aee"  # 企业ID



 
try:
    wxcpt = WXBizMsgCrypt(TOKEN, ENCODING_AES_KEY, CORP_ID)
except Exception as e:
    logger.error(f"初始化WXBizMsgCrypt失败: {str(e)}")
    raise
 
 
@app.get("/callback")
async def verify_url(msg_signature: str, timestamp: str, nonce: str, echostr: str):
    """验证URL有效性"""
    try:
        # 完整处理 echostr 的 URL 编码
        # 1. 先用 unquote_plus 处理 URL 编码（会自动将 + 处理好）
        # 2. 确保 Base64 的填充字符 = 正确
        logger.info(f"原始echostr: {echostr}")
        echostr = urllib.parse.unquote_plus(echostr)
        echostr = echostr.replace(" ", "+")
        logger.info(f"处理后的echostr: {echostr}")

        
        ret, sEchoStr = wxcpt.VerifyURL(msg_signature, timestamp, nonce, echostr)
        logger.info(f"处理后的echostr: {echostr}")
        logger.info(f"收到验证请求: msg_signature={msg_signature}, timestamp={timestamp}, nonce={nonce}")
        
 
        if ret == 0:
            logger.info("URL验证成功")
            return PlainTextResponse(content=sEchoStr)
        else:
            logger.error(f"URL验证失败，错误码: {ret}")
            raise HTTPException(status_code=400, detail="验证失败")
    except Exception as e:
        logger.error(f"验证过程发生错误: {str(e)}")
        raise HTTPException(status_code=500, detail="服务器内部错误")
 
 
@app.post("/callback")
async def receive_message(request: Request):
    """接收并处理企业微信消息"""
    try:
        # 获取请求参数
        body = await request.body()
        msg_signature = request.query_params.get("msg_signature")
        timestamp = request.query_params.get("timestamp")
        nonce = request.query_params.get("nonce")
 
        if not all([msg_signature, timestamp, nonce]):
            raise HTTPException(status_code=400, detail="缺少必要的参数")
            
        # URL解码处理
        msg_signature = urllib.parse.unquote(msg_signature)
        timestamp = urllib.parse.unquote(timestamp)
        nonce = urllib.parse.unquote(nonce)
 
        logger.info(f"收到消息推送: msg_signature={msg_signature}, timestamp={timestamp}, nonce={nonce}")
 
        # 解密消息
        ret, sMsg = wxcpt.DecryptMsg(body, msg_signature, timestamp, nonce)
        if ret != 0:
            logger.error(f"消息解密失败，错误码: {ret}")
            raise HTTPException(status_code=400, detail="消息解密失败")
 
        # 解析XML消息
        xml_dict = xmltodict.parse(sMsg)
        logger.info(f"解密后的消息内容: {xml_dict}")
 
        # 提取消息内容
        xml_content = xml_dict['xml']
        to_user_name = xml_content.get('ToUserName')
        from_user_name = xml_content.get('FromUserName')
        create_time = xml_content.get('CreateTime')
        msg_type = xml_content.get('MsgType')
        content = xml_content.get('Content')
        msg_id = xml_content.get('MsgId')
        agent_id = xml_content.get('AgentID')
 
        logger.info(f"收到消息: {content}")
 
        # 构造回复消息
        reply_content = "暂不支持当前内容回复" + content
        current_time = str(int(time.time()))
        reply_msg = f"""
        <xml>
            <ToUserName><![CDATA[{from_user_name}]]></ToUserName>
            <FromUserName><![CDATA[{to_user_name}]]></FromUserName>
            <CreateTime>{current_time}</CreateTime>
            <MsgType><![CDATA[{msg_type}]]></MsgType>
            <Content><![CDATA[{reply_content}]]></Content>
            <MsgId>{msg_id}</MsgId>
            <AgentID>{agent_id}</AgentID>
        </xml>
        """
 
        # 加密回复消息
        ret, encrypted_msg = wxcpt.EncryptMsg(reply_msg, nonce, current_time)
        if ret != 0:
            logger.error(f"消息加密失败，错误码: {ret}")
            raise HTTPException(status_code=500, detail="消息加密失败")
 
        logger.info("成功构造并加密回复消息")
        return Response(content=encrypted_msg, media_type="application/xml")
 
    except Exception as e:
        logger.error(f"处理消息时发生错误: {str(e)}")
        raise HTTPException(status_code=500, detail="服务器内部错误")
 
 
